package com.lei.study.depth.lock;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.util.concurrent.*;
import java.util.concurrent.locks.Lock;

/**
 * <p>
 * 测试锁
 * </p>
 *
 * @author <a href="mailto:17674030991@163.com">伍磊</a>
 */
public class LockTest {

    private static final Logger LOG = LoggerFactory.getLogger(LockTest.class);

    private static int STOCK = 1;

    public static void main(String[] args) throws InterruptedException {
        // 1. 测试单台机器 & 30线程 & 只有一个ZookeeperLock 抢 一个库存
        // -> 一个线程抢到了锁并且执行完然后释放掉，但是另一个线程还没有添加监听器，这时候多线程出现问题，监听器无法触发
        // test1();

        // 2. 测试 lockInterruptibly
        // testlLockInterruptibly();

        // 3. 测试 tryLock
        // testTryLock(null, null);

        // 4. 测试 tryLock 带有时间
        testTryLock(5, TimeUnit.SECONDS);
    }

    private static void testTryLock(Integer time, TimeUnit unit) {
        int count = 5;
        CyclicBarrier cyclicBarrier = new CyclicBarrier(count);
        ExecutorService executorService = Executors.newFixedThreadPool(count);
        for (int i = 0; i < count; i++) {
            executorService.execute(() -> {
                try {
                    cyclicBarrier.await();
                    Lock lock = new ZookeeperLock();
                    boolean locked;
                    if (time != null && unit != null) {
                        locked = lock.tryLock(time, unit);
                    } else {
                        locked = lock.tryLock();
                    }
                    if (locked) {
                        LOG.info("{} 获取锁成功!", Thread.currentThread().getName());
                        TimeUnit.SECONDS.sleep(1);
                        lock.unlock();
                    } else {
                        LOG.info("{} 获取锁失败!", Thread.currentThread().getName());
                    }
                } catch (InterruptedException | BrokenBarrierException e) {
                    e.printStackTrace();
                }
            });
        }
    }

    private static void testlLockInterruptibly() throws InterruptedException {
        Thread thread = new Thread(() -> {
            Lock lock = new ZookeeperLock();

            try {
                lock.lockInterruptibly();
                LOG.info("抢到锁啦...");
            } catch (InterruptedException e) {
                LOG.error("线程被中断了...");
            } finally {
                LOG.info("释放啦...");
                lock.unlock();
            }
        });

        // 主线程先抢到锁
        Lock lock = new ZookeeperLock();
        lock.lock();
        LOG.info("主线程抢到锁啦...");
        // 启动子线程抢锁
        thread.start();
        // 等待1秒
        TimeUnit.SECONDS.sleep(1);
        // 中断子线程
        thread.interrupt();
        // 主线程释放锁
        lock.unlock();
        LOG.info("主线程释放啦...");
    }

    @SuppressWarnings("all")
    private static void test1() {
        int count = 5;
        CyclicBarrier cyclicBarrier = new CyclicBarrier(count);
        ExecutorService executorService = Executors.newFixedThreadPool(count);
        for (int i = 0; i < count; i++) {
            executorService.execute(() -> {
                Lock lock = new ZookeeperLock();
                try {
                    cyclicBarrier.await();
                    // 获取锁
                    lock.lock();
                    LOG.info("{} 获取锁成功!", Thread.currentThread().getName());
                    //TimeUnit.SECONDS.sleep(1);
                    if (STOCK < 1) {
                        LOG.error("{} 扣减库存失败!", Thread.currentThread().getName());
                    } else {
                        STOCK--;
                        LOG.info("{} 扣减库存成功!", Thread.currentThread().getName());
                    }
                } catch (InterruptedException | BrokenBarrierException e) {
                    e.printStackTrace();
                } finally {
                    LOG.info("{} 释放锁成功!", Thread.currentThread().getName());
                    lock.unlock();
                }
            });
        }
    }
}
